<?php
/*
 * @Author: CHINAKAIYUAN<sunkaiyuan@namenode.cn>
 * @Date: 2022-02-02 19:42:06
 * @LastEditTime: 2023-11-11 15:43:54
 * @LastEditors: 孙开源 && sunkaiyuan@namenode.cn
 * @Description: 工序过数
 */

namespace App\Repositories;

use App\Models\BaseModel;
use App\Models\ProPlan;
use App\Models\ProProcesses;
use App\Models\ProProcessesPass;
use App\Models\ProProcessesStorage;
use App\Models\ProProcessesWip;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Facades\Image;

/**
 * @property ProProcesses $process
 * @property ProProcessesPass $model
 * @property ProProcessesWipRepository $wip
 * @property ProEmployeeProRepository $salay_pro
 * @author sunkaiyuan
 */
class ProProcessesPassRepository extends Repositories
    {
    public $relation_models = ["creator", "out_process", 'swipor', "process", 'pro_dept', 'out_pro_dept', 'outfactory', 'out_outfactory', "device", "open_card" => ["customer"]];

    public function boot(
        ProProcessesPass $model,
        ProProcesses $process,
        ProProcessesWipRepository $wip,
        ProEmployeeProRepository $salay_pro
    ) {
        $this->model     = $model;
        $this->process   = $process;
        $this->wip       = $wip;
        $this->salay_pro = $salay_pro;
        }

    protected function repairSwip($old_wip_storage)
        {
        $pro_yarn = $old_wip_storage->pro_plan->pro_yarn;
        //复修没有领纱单
        if ($pro_yarn && ($pro_yarn->took_id ?? 0) == 0 && ($pro_yarn->status_id ?? 0) == 0) {
            fail("未领纱 或者出库！禁止刷卡！");
            }
        //下一个流程是复修
        $next_process_id                       = 14;
        $faultle_quantity                      = $old_wip_storage->faultle_quantity;
        [$new_wip_storage, $scrap_wip_storage] = $this->wip->swipeWipToProcess($old_wip_storage, $next_process_id, 0, $faultle_quantity, $faultle_quantity, $old_wip_storage->pro_dept_id, null, 0, -1);

        $this->createPass($new_wip_storage, $scrap_wip_storage, $old_wip_storage, $faultle_quantity, $next_process_id, $old_wip_storage->pro_dept_id, 0, $faultle_quantity, null, null, -1, 0, 0, "");
        return $faultle_quantity;
        }
    protected function norepairSwip($old_wip_storage)
        {
        if ($old_wip_storage->process_id != 14) {
            fail("取消复修过数必须是复修WIP库存！");
            }
        $pass                                  = $this->whereScrap_wip_id($old_wip_storage->id)->first();
        $faultle_quantity                      = $old_wip_storage->faultle_quantity;
        [$new_wip_storage, $scrap_wip_storage] = $this->wip->swipeWipToProcess($old_wip_storage, $pass->out_process_id, $faultle_quantity, 0, $faultle_quantity, $pass->pro_dept_id, 0, 1);

        $newpass = $this->createPass($new_wip_storage, $scrap_wip_storage, $old_wip_storage, $faultle_quantity, $pass->out_process_id, $pass->pro_dept_id, $faultle_quantity, 0, null, null, 1, 0, 0, "");

        $pass->delete();
        $newpass->delete();
        return $faultle_quantity;
        }
    /**
     *  过数刷卡
     * @param mixed $wip_id             wip 库存
     * @param mixed $process_id         工序Id
     * @param mixed $faultle_quantity   刷卡正品数
     * @param mixed $rejects_quantity   刷卡次品数
     * @param mixed $direction_id          是否返工
     * @param mixed $pro_dept_id        加工车间
     * @param mixed $factory_id         wip 外发加工厂/返工，就是返工到哪个加工厂
     * @param mixed $out_quantity       WIP 出库数量 ,默认出库数量等于正品数量
     * @param mixed $location_id       过数的收货库存位置，倒毛收货根据库位部门权限
     * @return ProProcessesPass
     * @author sunkaiyuan
     */
    public function swipe(
        $wip_id,
        $faultle_quantity,
        $rejects_quantity = 0,
        $direction_id = 1,
        $pro_dept_id = null,
        $factory_id = null,
        $swipor_id = null,
        $swiped_at = null,
        $out_quantity = null,
        $location_id = 0,
        $device_id = 0,
        $remark = "",
    ) {
        //wip库存
        $old_wip_storage = $this->wip->getWip(['id' => $wip_id]);
        if ($old_wip_storage->open_card->main->bom_id == 0) {
            fail("流转卡【{$old_wip_storage->open_card->code}】没有配置BOM工艺！无法过数！");
            }
        //设备使用的是管理员账号 
        // if (time() - strtotime($old_wip_storage->updated_at) < 5 * 60 && auth()->user()->id == 1) {
        //     fail("3分钟内不允许重复刷卡！请稍后再试！");
        //     }
        $out_quantity = $out_quantity ?? ($faultle_quantity + $rejects_quantity);

        //下一个流程
        [$next_process, $route_process] = $this->wip->getNextProcessByWip($old_wip_storage, $direction_id);
        //过数
        if ($direction_id == 1 && $next_process->allow_out == 1) {
            if ($factory_id === null) {
                fail("[{$next_process->name}]工序允许外发！必须填写外发加工厂！");
                }
            }
        [$new_wip_storage, $scrap_wip_storage] = $this->wip->swipeWipToProcess($old_wip_storage, $next_process->id, $faultle_quantity, $rejects_quantity, $out_quantity, $pro_dept_id, $factory_id, $location_id, $direction_id, $remark);

        $new_wip_storage->open_card;
        //自动记产量
        $process_pro_id = 0;
        if ($direction_id == 1) {
            // dd($new_wip_storage);
            //autopro 自动记产量 direction_id==-1  是返工WIP，不记产量
            if ($new_wip_storage->process->autopro == 1 && $old_wip_storage->direction_id == 1)
                $process_pro_id = $this->salay_pro->add($swipor_id ?? $new_wip_storage->creator_id, $out_quantity * $direction_id, date("Y-m-d", strtotime($swiped_at ?? date("Y-m-d"))),$route_process->id);

            }

        return $this->createPass($new_wip_storage, $scrap_wip_storage, $old_wip_storage, $out_quantity, $next_process->id, $pro_dept_id, $faultle_quantity, $rejects_quantity, $swipor_id, $swiped_at, $direction_id, $process_pro_id, $device_id, $remark, $route_process);
        }


    public function deleteByWipIds($wip_ids)
        {

        $this->whereIn("wip_id", $wip_ids)->get()->filter(function ($pass_m)
            {
            $this->deletePass($pass_m->id);
            });

        }
    public function deletePass($pass_id)
        {
        $pass_data = $this->whereId($pass_id)->first();
        if ($pass_data) {
            //如果是创建了关联单据，删除单据
            // DB::enableQueryLog();
            $open_card = $pass_data->open_card;
            // dd(DB::getQueryLog());
            if ($open_card->process_id == 14) {
                fail("单据已复修！禁止操作！");
                }
            $wip_data = $this->wip->getWip(['id' => $pass_data->wip_id]);

            $this->deleteRelation($pass_data->target, $wip_data);
            // 0 - $pass_data->direction_id  是返工过数，删除就是正向
            [$next_process, $route_process] = $this->wip->getNextProcessByWip($wip_data, 0 - $pass_data->direction_id);
            if ($next_process->id == 0) {
                fail("最后一步刷卡工序，不能删除！");
                }
            if (($pass_data->scrap_wip_id ?? 0) > 0) {
                $scrapwip_data = $this->wip->getWip(['id' => $pass_data->scrap_wip_id]);
                //复修不入库
                // $this->wip->removeInspectIfEnd($scrapwip_data);
                $this->wip->subWipStorage($scrapwip_data, $pass_data->rejects_quantity);
                }

            $this->wip->subWipStorage($wip_data, $pass_data->faultle_quantity);

            $this->wip->restoreWip($pass_data->out_wip_id, $pass_data->out_quantity);

            if ($wip_data->process->autopro == 1 && $wip_data->direction_id == 1)
                $this->salay_pro->add($pass_data->swipor_id, 0 - $pass_data->open_card->quantity, $pass_data->swiped_at,$route_process->id);


            // dd(DB::getQueryLog());
            $open_card->scheduling->filter(function ($v) use ($open_card)
                {
                if ($open_card->processrename->rename == $v->process_name) {
                    auditSave($v, false);
                    }
                });

            $open_card->process_id       = $next_process->id;
            $open_card->route_process_id = $route_process->id;
            $open_card->save();
            $order = $open_card->order;
            if ($order) {
                $order->process_id       = $next_process->id;
                $order->route_process_id = $route_process->id;
                $order->updateQuantity();
                $order->save();
                }
            $pass_data->delete();
            }
        else {
            fail("意外错误！丢失pass_id!");
            }
        }
    private function createPass(
        $new_wip_storage,
        $scrap_wip_storage,
        $old_wip_storage,
        $out_quantity,
        $next_process_id,
        $pro_dept_id,
        $faultle_quantity,
        $rejects_quantity,
        $swipor_id,
        $swiped_at,
        $direction_id,
        $process_pro_id,
        $device_id,
        $remark,
        $route_process = null
    ) {
        $open_card    = $new_wip_storage->open_card;
        $process_pass = $this->create([
            'open_card_id'         => $new_wip_storage?->open_card_id ?? $scrap_wip_storage->open_card_id,
            'wip_id'               => $new_wip_storage?->id,
            'scrap_wip_id'         => $scrap_wip_storage?->id,
            'device_id'            => $device_id,
            'remark'               => $remark,
            //出 WIP库存
            'out_wip_id'           => $old_wip_storage->id,
            //出 工序
            'out_process_id'       => $old_wip_storage->process_id,
            //出加工厂
            'out_outfactory_id'    => $old_wip_storage->outfactory_id,
            //出车间
            'out_pro_dept_id'      => $old_wip_storage->pro_dept_id,
            //车间
            'pro_dept_id'          => $pro_dept_id,
            //出 数
            'out_quantity'         => $out_quantity,
            //计数工序
            'process_id'           => $next_process_id,
            //工序别名
            'route_process_id'     => $route_process->id,
            //工序别名
            'out_route_process_id' => $open_card?->route_process_id,
            //入 加工厂
            'outfactory_id'        => $new_wip_storage?->factory_id ?? 0,
            'dyelot'               => $new_wip_storage?->dyelot ?? $scrap_wip_storage?->dyelot ?? "",
            'faultle_quantity'     => $faultle_quantity,
            'rejects_quantity'     => $rejects_quantity,
            'swipor_id'            => $swipor_id ?? ($new_wip_storage?->creator_id ?? $scrap_wip_storage->creator_id),
            'swiped_at'            => $swiped_at ?? ($new_wip_storage?->created_at ?? $scrap_wip_storage->created_at),
            'direction_id'         => $direction_id,
            'process_pro_id'       => $process_pro_id,
            //WIP 是返工出来的，不计产量
            'ignore_pro'           => $direction_id == -1 ? -1 : $old_wip_storage->direction_id
        ]);
        if ($new_wip_storage) {
            //老WIP 是车间的，新的WIP 也是车间的，尝试创建检验入库
            //老WIP 是车间的，新的WIP 是外加工厂的,创建外发计划
            $targetModel = false;
            if ($direction_id == 1 && $old_wip_storage->pro_dept_id > 0 && $old_wip_storage->outfactory_id == 0 && $new_wip_storage->pro_dept_id == 0 && $new_wip_storage->outfactory_id > 0) {
                $targetModel = $this->createPlan($new_wip_storage, $process_pass->id);
                }
            //老WIP 是外发的，新的WIP 是车间的,创建收货
            if ($old_wip_storage->outfactory_id > 0 && $new_wip_storage->outfactory_id == 0) {
                $targetModel = $this->createRecive($new_wip_storage, $old_wip_storage, $process_pass->id, $direction_id, $out_quantity);
                }
            if ($targetModel) {
                $process_pass->target_model = $targetModel::class;
                $process_pass->target_value = $targetModel->id;
                }

            $this->wip->createInpsectIfEnd($new_wip_storage, $process_pass->id);

            $process_pass->save();
            }
        //更新刷卡
        // DB::enableQueryLog();


        $order = $open_card->order;

        // dd(DB::getQueryLog());
        $open_card->process_id = $next_process_id;
        $route_process && $open_card->route_process_id = $route_process->id;
        $open_card->save();
        //回修没有订单
        if ($order) {
            $order->process_id = $next_process_id;
            $route_process && $order->route_process_id = $route_process->id;
            $order->updateQuantity();
            $order->save();
            }
        return $process_pass;
        }
    public function deleteRelation($target, $wip_data)
        {
        $this->wip->removeInspectIfAudit($wip_data);
        $this->removePlan($target);
        $this->removeRecive($target);
        }
    public function removePlan($plan)
        {
        if ($plan instanceof ProPlan) {
            $plan->delete();
            }
        }
    public function removeRecive($target)
        {
        if ($target instanceof ProProcessesStorage) {
            $target->delete();
            }
        }
    public function createRecive($new_wip_storage, $old_wip_storage, $pass_id, $direction_id, $out_quantity)
        {
        $plan = $new_wip_storage->pro_plan;
        return ProProcessesStorageRepository::create([
            'pass_id'                     => $pass_id,
            'outfactory_id'               => $old_wip_storage->outfactory_id,
            'order_user_id'               => $plan->order_user_id,
            'department_id'               => $plan->department_id,
            'open_card_id'                => $plan->open_card_id,
            'process_id'                  => $plan->process_id,
            'location_id'                 => $new_wip_storage->location_id,
            'material_id'                 => $new_wip_storage->material_id,
            'lot_id'                      => $new_wip_storage->lot_id,
            'lot_name'                    => $plan->lot_name,
            'color_name'                  => $plan->color_name,
            'dyelot'                      => $new_wip_storage->dyelot,
            'company_id'                  => $plan->company_id,
            'remark'                      => $plan->remark,
            'quantity'                    => $new_wip_storage->faultle_quantity,
            'auxiliary_quantity'          => $new_wip_storage->auxiliary_quantity ?? $new_wip_storage->faultle_quantity / 25,
            'material_quantity'           => $out_quantity,
            'material_auxiliary_quantity' => $out_quantity / 25,
            'order_code'                  => $plan->order_code,
            'direction_id'                => $direction_id,
            'pro_dept_id'                 => $plan->pro_dept_id,
            'process_route_id'            => $plan->process_route_id,
            'isrepair'                    => $new_wip_storage->is_scrap,
        ]);
        }
    public function createPlan($new_wip_storage, $pass_id)
        {
        $plan = $new_wip_storage->pro_plan;

        return ProPlanRepository::create([
            'pass_id'                 => $pass_id,
            'pro_dept_id'             => 0,
            'order_code'              => $plan->order_code,
            'plan_id'                 => 2,
            'order_id'                => $plan->order_id,
            'open_card_id'            => $plan->open_card_id,
            'department_id'           => $plan->department_id,
            'feeding_ratio'           => $plan->feeding_ratio,
            'material_id'             => $plan->material_id,
            'process_id'              => $plan->process_id,
            'process_route_id'        => $plan->process_route_id,
            'lot_name'                => $plan->lot_name,
            'lot_id'                  => $plan->lot_id,
            'color_name'              => $plan->color_name,
            'loom_id'                 => $plan->loom_id,
            'emergency_id'            => $plan->emergency_id,
            'remark'                  => $plan->remark,
            'dgremark'                => $plan->dgremark,
            'company_id'              => $plan->company_id,
            'plan_quantity'           => $new_wip_storage->faultle_quantity,
            'plan_auxiliary_quantity' => $new_wip_storage->faultle_auxiliary_quantity ?? $new_wip_storage->faultle_quantity / 25,
            'pro_quantity'            => $new_wip_storage->faultle_quantity,
            'order_user_id'           => $plan->order_user_id,
            'outfactory_id'           => $new_wip_storage->outfactory_id,
            'classgroup_id'           => $plan->classgroup_id,
            'dyelot'                  => $new_wip_storage->dyelot,
            'location_id'             => $new_wip_storage->location_id,
            'isrepair'                => $new_wip_storage->is_scrap,
        ]);
        }

    /**
     * 初始化一个计划的工序过数，默认流程ID  在计划上
     * @param \App\Models\BaseModel $plan
     * @return ProProcessesPass
     * @author sunkaiyuan
     */
    public function init(BaseModel $plan)
        {
        $wip_data = $this->wip->getWip([
            'dyelot'       => $plan->dyelot,
            'color_name'   => $plan->color_name,
            'process_id'   => $plan->process_id,
            'open_card_id' => $plan->id,
            'pro_dept_id'  => 3,
        ], [
            'open_card_id'     => $plan->id,
            'dyelot'           => $plan->dyelot,
            'color_name'       => $plan->color_name,
            'material_id'      => $plan->material_id,
            'batchno'          => $plan->batchno,
            'faultle_quantity' => $plan->quantity,
            'process_id'       => $plan->process_id,
            'company_id'       => $plan->customer_id,
            'pro_dept_id'      => 3,
        ]);

        $process_pass = $this->create([
            'open_card_id'     => $plan->id,
            'wip_id'           => $wip_data->id,
            'process_id'       => $plan->process_id,
            'dyelot'           => $plan->dyelot,
            'color_name'       => $plan->color_name,
            'faultle_quantity' => $plan->quantity,
            'batchno'          => $plan->batchno,
            'process_pro_id'   => 0,
            'rejects_quantity' => 0,
            'swipor_id'        => $plan->creator_id,
            'swiped_at'        => $plan->created_at,
            'direction_id'     => 1,
            'pro_dept_id'      => 3,
        ]);
        $open_card    = $process_pass->open_card;

        $order = $open_card->order;
        $route = $wip_data->open_card->main->process_route->details()->orderBy("sort")->first();
        // dd(DB::getQueryLog());
        $open_card->process_id       = $route->process_id;
        $open_card->route_process_id = $route->id;
        $open_card->save();
        //回修没有订单
        if ($order) {
            $order->process_id       = $process_pass->process_id;
            $order->route_process_id = $route->id;
            $order->save();
            }

        return $process_pass;
        }
    }
